#include "Pch.h"
#include "UnitTestUtility.h"

#ifdef _WIN32
#include <mbctype.h>
#endif

LocaleOverrider::LocaleOverrider(char* pszLocale, int nCodePage)
{
#ifdef _WIN32
    m_nOldPageCode = _getmbcp();
    _setmbcp(nCodePage);
#endif

    // Save the old locale
    m_oldLocale = setlocale(LC_ALL, NULL);
    setlocale(LC_ALL, pszLocale);
}

LocaleOverrider::~LocaleOverrider()
{
    // Restore locale
    if( !m_oldLocale.empty() )
        setlocale( LC_ALL, m_oldLocale.c_str() );

#ifdef _WIN32
    _setmbcp(m_nOldPageCode);
#endif
}

bool UnitTestUtil::PointsEqual(FdoIPoint * point1, FdoIPoint * point2)
{
    FdoPtr<FdoIDirectPosition> pPos1 = point1->GetPosition();
    FdoPtr<FdoIDirectPosition> pPos2 = point2->GetPosition();

    double x1 = pPos1->GetX();
    double y1 = pPos1->GetY();
    double x2 = pPos2->GetX();
    double y2 = pPos2->GetY();

    if(!FuzzyEqual(pPos1->GetX(), pPos2->GetX()))
        return false;

    return FuzzyEqual(pPos1->GetY(), pPos2->GetY());
}

bool UnitTestUtil::PointsEqual(FdoIGeometry * geom1, FdoIGeometry * geom2)
{
    FdoIPoint* p1 = (FdoIPoint*)geom1;
    FdoIPoint* p2 = (FdoIPoint*)geom2;
    return PointsEqual(p1, p2);
}

bool UnitTestUtil::MultiPointsEqual(FdoIMultiPoint * point1, FdoIMultiPoint * point2)
{
    FdoInt32 count1 = point1->GetCount();
    FdoInt32 count2 = point2->GetCount();
    if (count1 != count2)
        return false;

    for (int i = 0; i < count1; ++i)
    {
        FdoPtr<FdoIPoint> p1 = point1->GetItem(i);
        FdoPtr<FdoIPoint> p2 = point2->GetItem(i);
        if (!PointsEqual(p1, p2))
            return false;
    }
    return true;
}

bool UnitTestUtil::MultiPointsEqual(FdoIGeometry * geom1, FdoIGeometry * geom2)
{
    FdoIMultiPoint* p1 = (FdoIMultiPoint*)geom1;
    FdoIMultiPoint* p2 = (FdoIMultiPoint*)geom2;
    return MultiPointsEqual(p1, p2);
}

bool UnitTestUtil::LineEqual(FdoIGeometry * geom1, FdoIGeometry * geom2)
{
    FdoILineString* l1 = (FdoILineString*)geom1;
    FdoILineString* l2 = (FdoILineString*)geom2;
    FdoInt32 iCount1 = l1->GetCount();
    FdoInt32 iCount2 = l2->GetCount();
    if (iCount1 != iCount2)
        return false;
    for (FdoInt32 i=0; i<iCount1; i++)
    {
        FdoPtr<FdoIDirectPosition> pos1 = l1->GetItem(i);
        FdoPtr<FdoIDirectPosition> pos2 = l2->GetItem(i);
        if (!PointsEquivalent(pos1, pos2))
            return false;
    }

    return true;
}

bool UnitTestUtil::MultiLineStringEqual(FdoIGeometry * geom1, FdoIGeometry * geom2)
{
    FdoIMultiLineString* multi1 = (FdoIMultiLineString*)geom1;
    FdoIMultiLineString* multi2 = (FdoIMultiLineString*)geom2;
    FdoInt32 count1 = multi1->GetCount();
    FdoInt32 count2 = multi2->GetCount();
    if (count1 != count2)
        return false;
    for (FdoInt32 i=0; i<count1; i++)
    {
        FdoPtr<FdoIGeometry> item1 = multi1->GetItem(i);
        FdoPtr<FdoIGeometry> item2 = multi2->GetItem(i);
        if (!LineEqual(item1,item2))
            return false;
    }

    return true;
}

bool UnitTestUtil::PolygonEqual(FdoIGeometry * geom1, FdoIGeometry * geom2)
{
    FdoIPolygon* p1 = (FdoIPolygon*)geom1;
    FdoIPolygon* p2 = (FdoIPolygon*)geom2;
    FdoPtr<FdoILinearRing> ring1 = p1->GetExteriorRing();
    FdoPtr<FdoILinearRing> ring2 = p2->GetExteriorRing();
    if (!LinearRingsEquivalent(ring1, ring2))
        return false;
    FdoInt32 iIntRingCount1 = p1->GetInteriorRingCount();
    FdoInt32 iIntRingCount2 = p2->GetInteriorRingCount();
    if (iIntRingCount1 != iIntRingCount2)
        return false;
    for (FdoInt32 i=0; i<iIntRingCount1; i++)
    {
        ring1 = p1->GetInteriorRing(i);
        ring2 = p2->GetInteriorRing(i);
        if (!LinearRingsEquivalent(ring1, ring2))
            return false;
    }
    return true;
}

bool UnitTestUtil::MultiPolygonEqual(FdoIGeometry * geom1, FdoIGeometry * geom2)
{
    FdoIMultiPolygon* multi1 = (FdoIMultiPolygon*)geom1;
    FdoIMultiPolygon* multi2 = (FdoIMultiPolygon*)geom2;
    FdoInt32 count1 = multi1->GetCount();
    FdoInt32 count2 = multi2->GetCount();
    if (count1 != count2)
        return false;
    for (FdoInt32 i=0; i<count1; i++)
    {
        FdoPtr<FdoIGeometry> item1 = multi1->GetItem(i);
        FdoPtr<FdoIGeometry> item2 = multi2->GetItem(i);
        if (!PolygonEqual(item1,item2))
            return false;
    }

    return true;
}

bool UnitTestUtil::MultiGeometryEqual(FdoIGeometry * geom1, FdoIGeometry * geom2)
{
    FdoIMultiGeometry* multi1 = (FdoIMultiGeometry*)geom1;
    FdoIMultiGeometry* multi2 = (FdoIMultiGeometry*)geom2;
    FdoInt32 count1 = multi1->GetCount();
    FdoInt32 count2 = multi2->GetCount();
    if (count1 != count2)
        return false;

    for (FdoInt32 i=0; i<count1; i++)
    {
        FdoPtr<FdoIGeometry> item1 = multi1->GetItem(i);
        FdoPtr<FdoIGeometry> item2 = multi2->GetItem(i);
        switch(item1->GetDerivedType())
        {
            case FdoGeometryType_Point:
                return PointsEqual(item1, item2);
                break;
            case FdoGeometryType_LineString:
                return LineEqual(item1, item2);
                break;
            case FdoGeometryType_Polygon:
                return PolygonEqual(item1, item2);
                break;
            case FdoGeometryType_MultiPoint:
                return MultiPointsEqual(item1, item2);
                break;
            case FdoGeometryType_MultiLineString:
                return MultiLineStringEqual(item1, item2);
                break;
            case FdoGeometryType_MultiPolygon:
                return MultiLineStringEqual(item1, item2);
                break;
            case FdoGeometryType_MultiGeometry:
            case FdoGeometryType_None:
            case FdoGeometryType_CurveString:
            case FdoGeometryType_CurvePolygon:
            case FdoGeometryType_MultiCurveString:
            case FdoGeometryType_MultiCurvePolygon:
                return false;
                break;
            default:
                return false;
                break;
        }
    }

    return false;
}

bool UnitTestUtil::PointsEquivalent(FdoIDirectPosition * point1, FdoIDirectPosition * point2)
{
    if(!FuzzyEqual(point1->GetX(), point2->GetX()))
        return false;

    return FuzzyEqual(point1->GetY(), point2->GetY());
}

bool UnitTestUtil::LinearRingsEquivalent(FdoILinearRing* lr1, FdoILinearRing* lr2)
{
    FdoInt32 count1 = lr1->GetCount();
    FdoInt32 count2 = lr2->GetCount();
    if (count1 != count2)
        return false;

    // Compare all the points in the 2 linear rings:
    for (FdoInt32 i=0; i<count1; i++)
    {
        FdoPtr<FdoIDirectPosition> pos1 = lr1->GetItem(i);
        FdoPtr<FdoIDirectPosition> pos2 = lr2->GetItem(i);
        if (!PointsEquivalent(pos1,pos2))
            return false;
    }

    return true;
}

bool UnitTestUtil::FuzzyEqual (const double d1, const double d2)
{
    if ((d1==0.0) || (d2==0.0))
        return 1.0/33 > fabs(d1 - d2);
    else
        return 1.0/33 > fabs(1.0 - (d2 / d1));
}
